package com.liyasong.cf;

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.similarity.AbstractItemSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.model.PreferenceArray;


public class MySimilarity extends AbstractItemSimilarity {

	public MySimilarity(DataModel dataModel) {
		super(dataModel);
	}

	public double itemSimilarity(long itemID1, long itemID2)
			throws TasteException {
	    DataModel dataModel = getDataModel();
	    PreferenceArray xPrefs = dataModel.getPreferencesForItem(itemID1);
	    PreferenceArray yPrefs = dataModel.getPreferencesForItem(itemID2);
	    int xLength = xPrefs.length();
	    int yLength = yPrefs.length();
	    
	    if (xLength == 0 || yLength == 0) {
	      return Double.NaN;
	    }
	    
	    long xIndex = xPrefs.getUserID(0);
	    long yIndex = yPrefs.getUserID(0);
	    int xPrefIndex = 0;
	    int yPrefIndex = 0;
	    
	    double sumX = 0.0;
	    double sumX2 = 0.0;
	    double sumY = 0.0;
	    double sumY2 = 0.0;
	    double sumXY = 0.0;
	    double sumXYdiff2 = 0.0;
	    int count = 0;
	    
	    // No, pref inferrers and transforms don't appy here. I think.
	    
	    while (true) {
	      int compare = xIndex < yIndex ? -1 : xIndex > yIndex ? 1 : 0;
	      if (compare == 0) {
	        // Both users expressed a preference for the item
	        double x = xPrefs.getValue(xPrefIndex);
	        double y = yPrefs.getValue(yPrefIndex);
	        sumXY += x * y;
	        sumX += x;
	        sumX2 += x * x;
	        sumY += y;
	        sumY2 += y * y;
	        double diff = x - y;
	        sumXYdiff2 += diff * diff;
	        count++;
	      }
	      if (compare <= 0) {
	        if (++xPrefIndex == xLength) {
	          break;
	        }
	        xIndex = xPrefs.getUserID(xPrefIndex);
	      }
	      if (compare >= 0) {
	        if (++yPrefIndex == yLength) {
	          break;
	        }
	        yIndex = yPrefs.getUserID(yPrefIndex);
	      }
	    }
	    
	    if (count == 0) {
	        return Double.NaN;
	    }
	    
	    double n = (double) count;
	    double meanX = sumX / n;
	    double meanY = sumY / n;
	      // double centeredSumXY = sumXY - meanY * sumX - meanX * sumY + n * meanX * meanY;
	    double centeredSumXY = sumXY - meanY * sumX;
        // double centeredSumX2 = sumX2 - 2.0 * meanX * sumX + n * meanX * meanX;
        double centeredSumX2 = sumX2 - meanX * sumX;
	      // double centeredSumY2 = sumY2 - 2.0 * meanY * sumY + n * meanY * meanY;
        double centeredSumY2 = sumY2 - meanY * sumY;
	   
	    double denominator = Math.sqrt(centeredSumX2) * Math.sqrt(centeredSumY2);
	    if (denominator == 0.0) {
	        return Double.NaN;
	    }
        return centeredSumXY / denominator;
	}

	public double[] itemSimilarities(long itemID1, long[] itemID2s)
			throws TasteException {
		// TODO Auto-generated method stub
		return null;
	}

}
